#include "ForLoop.h"
#include "../Exceptions.h"
#include "../GeneralVisitor.h"

ForLoop::ForLoop(TreeNode* iInitialAssign, TreeNode* iCondition, TreeNode* iBody, TreeNode* iAfterBodyAssignment)
{
    this->fInitialAssign = iInitialAssign;
    this->fCondition = iCondition;
    this->fBody = iBody;
    this->fAfterBodyAssignment = iAfterBodyAssignment;
}

ForLoop::~ForLoop()
{
    delete this->fInitialAssign;
    delete this->fCondition;
    delete this->fBody;
    delete this->fAfterBodyAssignment;
}

void ForLoop::CheckVariables(set<string>& oVariables, string iParentName)
{
    // kdybychom podporovali deklaraci promennych ve stylu:
    /* 
    for(int i = 0; i < 10; i++)
    {
    }
    */
    // tak by to bylo slozitejsi, protoze to 'i' je pak platne jen uvnitr cyklu
    // ale mozna ne - stacilo by nejdriv do setu tu promennou vlozit a na konci ji zase odebrat)
    // uvnitr cyklu by tak byla videt, ale za cyklem uz ne (HA!)

    this->fInitialAssign->CheckVariables(oVariables, iParentName);
    this->fCondition->CheckVariables(oVariables, iParentName);
    this->fBody->CheckVariables(oVariables, iParentName);
    this->fAfterBodyAssignment->CheckVariables(oVariables, iParentName);
}

void ForLoop::CheckFunctionCalls(set<FunctionDefinition*>& iAllFunctions, string iParentName)
{
    this->fInitialAssign->CheckFunctionCalls(iAllFunctions, iParentName);
    this->fCondition->CheckFunctionCalls(iAllFunctions, iParentName);
    this->fBody->CheckFunctionCalls(iAllFunctions, iParentName);
    this->fAfterBodyAssignment->CheckFunctionCalls(iAllFunctions, iParentName);
}

void ForLoop::CheckClassConstructions(set<ClassDefinition*>& iAllClasses, string iParentName)
{
    this->fInitialAssign->CheckClassConstructions(iAllClasses, iParentName);
    this->fCondition->CheckClassConstructions(iAllClasses, iParentName);
    this->fBody->CheckClassConstructions(iAllClasses, iParentName);
    this->fAfterBodyAssignment->CheckClassConstructions(iAllClasses, iParentName);
}

void ForLoop::CheckExpressionTypes(map<string, ExpressionType*>& iVarTypes, string iParentName)
{
    this->fInitialAssign->CheckExpressionTypes(iVarTypes, iParentName);
    this->fCondition->CheckExpressionTypes(iVarTypes, iParentName);
    this->fBody->CheckExpressionTypes(iVarTypes, iParentName);
    this->fAfterBodyAssignment->CheckExpressionTypes(iVarTypes, iParentName);

    ExpressionType* lConditionType = this->fCondition->GetType(iVarTypes, iParentName);
    ValueType lGot = lConditionType->fType;

    if(!lConditionType->fResolveTypeAtRuntime && lGot != Boolean)
    {
        delete lConditionType;
        throw InvalidTypeException(iParentName, "podminka cyklu for", Boolean, lGot);
    }

    delete lConditionType;
}

void ForLoop::Accept(GeneralVisitor* iVisitor)
{
    iVisitor->Visit(this);
}

ReturnStatement* ForLoop::GetFirstReturnStatement()
{
    return fBody->GetFirstReturnStatement();
}
